package vip.xiaonuo.biz.modular.scan.service.impl;

import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.NumberUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import vip.xiaonuo.auth.core.util.StpClientUtil;
import vip.xiaonuo.biz.modular.apilog.entity.DevApiLog;
import vip.xiaonuo.biz.modular.apilog.mapper.DevApiLogMapper;
import vip.xiaonuo.biz.modular.cabinetdoor.mapper.BizCabinetDoorMapper;
import vip.xiaonuo.biz.modular.cabinetdoor.vo.BizCabinetDoorResp;
import vip.xiaonuo.biz.modular.goods.entity.BizGoods;
import vip.xiaonuo.biz.modular.goods.entity.BizGoodsLedger;
import vip.xiaonuo.biz.modular.goods.mapper.BizGoodsLedgerMapper;
import vip.xiaonuo.biz.modular.goods.mapper.BizGoodsMapper;
import vip.xiaonuo.biz.modular.goods.result.GoodsLedgerPageResult;
import vip.xiaonuo.biz.modular.goods.service.BizGoodsLedgerCheckService;
import vip.xiaonuo.biz.modular.goods.service.BizGoodsService;
import vip.xiaonuo.biz.modular.scan.param.ScanDto;
import vip.xiaonuo.biz.modular.scan.param.ScanItemDto;
import vip.xiaonuo.biz.modular.scan.service.ScanEventService;
import vip.xiaonuo.biz.modular.scan.service.ScanService;
import vip.xiaonuo.common.exception.CommonException;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author 墨塵
 * @since 2023/10/31
 */
@Service
@Transactional
public class ScanServiceImpl implements ScanService {

    @Resource
    private DevApiLogMapper devApiLogMapper;

    @Resource
    private BizGoodsMapper bizGoodsMapper;

    @Resource
    private BizCabinetDoorMapper bizCabinetDoorMapper;

    @Resource
    private ScanEventService scanEventService;

    @Resource
    private BizGoodsService bizGoodsService;

    @Resource
    private BizGoodsLedgerMapper bizGoodsLedgerMapper;

    @Resource
    private BizGoodsLedgerCheckService bizGoodsLedgerCheckService;

    @Override
    public int scanForSto(ScanDto dto) {
        //校验部分
        if (StringUtils.isBlank(dto.getCabinetCode())) {
            throw new CommonException("缺失参数:cabinetCode");
        }
        if (StringUtils.isBlank(dto.getCabinetDoorCode())) {
            throw new CommonException("缺失参数:cabinetDoorCode");
        }
        if (null == dto.getGoodsType()) {
            throw new CommonException("缺失参数:goodsType");
        }
        if (CollectionUtils.isEmpty(dto.getItemList())) {
            throw new CommonException("缺失参数:itemList");
        }
        String goodsIds = dto.getItemList().stream().map(ScanItemDto::getGoodsId).collect(Collectors.joining(","));
        String reagentWeights = dto.getItemList().stream().map(ScanItemDto::getWeigh).collect(Collectors.joining(","));

        List<String> idList = dto.getItemList().stream().map(ScanItemDto::getGoodsId).collect(Collectors.toList());

        //当前用户
        String userId = StpClientUtil.getLoginIdAsString();
        //记录日志
        DevApiLog devApiLog = new DevApiLog();
        devApiLog.setCabinetCode(dto.getCabinetCode());
        devApiLog.setCabinetDoorCode(dto.getCabinetDoorCode());
        devApiLog.setUserId(userId);
        devApiLog.setReqType(97);
        devApiLog.setEventTime(new Date());
        devApiLog.setCreateTime(new Date());
        devApiLog.setGoodsIds(goodsIds);
        devApiLog.setReagentWeights(reagentWeights);
        devApiLogMapper.insert(devApiLog);
        //=============处理事件===================

        //获取柜子信息
        BizCabinetDoorResp cabinetDoorResp = bizCabinetDoorMapper.getInfoByCabCodeAndCabDoorCode(dto.getCabinetCode(), dto.getCabinetDoorCode());

        //更新物品存放柜子信息
        bizGoodsMapper.updateCabInfoForGoodsByIds(idList, cabinetDoorResp.getCabinetGroupId(), cabinetDoorResp.getCabinetInfoId(), cabinetDoorResp.getId());
        //判断一致性和非一致性
        bizGoodsMapper.updateStoAbcForGoodsByIds(idList);
        bizGoodsMapper.updateToStoAbcForGoodsByIds(idList);
        //获取物品列表
        List<BizGoods> goodsList = bizGoodsMapper.getListByIds(idList);
        //获取物品未入柜的列表
        List<BizGoods> notInCabList = goodsList.stream().filter(item -> item.getEnterFlag() == 0).collect(Collectors.toList());
        //触发事件-首次入柜
        scanEventService.addRecordForGoodsFirstInCab(notInCabList, devApiLog);
        //处理试剂相关事件
        scanEventService.handleReagentInCabFirst(dto, devApiLog);
        //针对所属柜子信息为空情况下-更新物品所属柜子信息
        for (BizGoods goods : goodsList) {
            if (StringUtils.isBlank(goods.getBioCabinetDoorId()) && StringUtils.isBlank(goods.getBioCabinetId()) && StringUtils.isBlank(goods.getBioCabinetGroupId())) {
                bizGoodsMapper.updateCabInfoForGoodsId(goods.getId(), cabinetDoorResp.getCabinetGroupId(), cabinetDoorResp.getCabinetInfoId(), cabinetDoorResp.getId());
            }
        }
        //更新物品入库标识
        bizGoodsMapper.updateEnterFlagByIds(idList);
        //触发事件-报废物品入柜
        scanEventService.addRecordForScrapiGoodsInCab(goodsList, devApiLog);
        //处理试剂柜超重相关试剂
        scanEventService.handleCabWeight(dto, devApiLog);
        //处理试剂存储属性冲突
        scanEventService.handleReagentClassClash(dto, devApiLog);
        return idList.size();
    }

    @Override
    public int scanForBor(ScanDto dto) {
        int result = 0;
        if (StringUtils.isBlank(dto.getGoodsId())) {
            throw new CommonException("缺失参数:goodsId");
        }
        //获取物品信息
        BizGoods goods = bizGoodsMapper.selectById(dto.getGoodsId());
        if (null == goods) {
            throw new CommonException("物品信息不存在=>" + dto.getGoodsId());
        }
        if (goods.getEnterFlag() == 0) {
            throw new CommonException("管理员扫码入库后方可借用");
        }
        if (goods.getLeaveFlag() == 1) {
            throw new CommonException("归还后方可借用");
        }
        if (goods.getSsbrFlag() == 0) {
            throw new CommonException("不支持扫码借出");
        }
        //当前用户
        String userId = StpClientUtil.getLoginIdAsString();
        //获取柜子信息
        BizCabinetDoorResp cabinetDoorResp = bizCabinetDoorMapper.getInfoByCabIdAndCabDoorId(goods.getCurCabinetId(), goods.getCurCabinetDoorId());
        //记录日志
        DevApiLog devApiLog = new DevApiLog();
        if (null != cabinetDoorResp) {
            devApiLog.setCabinetCode(cabinetDoorResp.getCabinetCode());
            devApiLog.setCabinetDoorCode(cabinetDoorResp.getCabinetDoorCode());
        }
        devApiLog.setUserId(userId);
        devApiLog.setReqType(96);
        devApiLog.setEventTime(new Date());
        devApiLog.setCreateTime(new Date());
        devApiLog.setGoodsIds(dto.getGoodsId());
        devApiLog.setReagentWeight(dto.getWeigh());
        devApiLog.setReagentWeights(dto.getWeigh());
        devApiLogMapper.insert(devApiLog);
        //更新物品借出
        bizGoodsMapper.updateForLendByIds(Arrays.asList(dto.getGoodsId()));
        //记录台账
        BizGoodsLedger goodsLedger = new BizGoodsLedger();
        goodsLedger.setApiLogId(devApiLog.getId());
        goodsLedger.setLedgerType(10);
        goodsLedger.setGoodsId(goods.getId());
        goodsLedger.setCurCabinetGroupId(cabinetDoorResp.getCabinetGroupId());
        goodsLedger.setCurCabinetId(cabinetDoorResp.getCabinetInfoId());
        goodsLedger.setCurCabinetDoorId(cabinetDoorResp.getId());
        goodsLedger.setDeliveryTime(devApiLog.getEventTime());
        goodsLedger.setDeliveryUserId(userId);
        goodsLedger.setReturnTime(bizGoodsService.getReturnTime(goods, devApiLog.getEventTime()));
        goodsLedger.setReturnFlag(0);
        goodsLedger.setCreateUser(devApiLog.getUserId());
        if (goods.getGoodsType() == 1) {
            goodsLedger.setReagentOutApiId(devApiLog.getId());
            Assert.notEmpty(dto.getWeigh(), "试剂毛重不能为空");
            if (StringUtils.isNotBlank(dto.getWeigh())) {
                String outWeight = dto.getWeigh();
                if (goods.getReagentContainerWeight() != null) {
                    //有容器重量时候计算毛重
                    outWeight = NumberUtil.round(NumberUtil.sub(outWeight, goods.getReagentContainerWeight().toString()), 2).toString();
                }
                goodsLedger.setReagentOutWeight(outWeight);
                if (goods.getReagentDensity() != null) {
                    goodsLedger.setReagentOutVolume(NumberUtil.div(outWeight, goods.getReagentDensity().toString(), 2).toString());
                }
            }
        }
        int count = bizGoodsLedgerMapper.insert(goodsLedger);
        result = result + count;
        //记录对应检查项
        bizGoodsLedgerCheckService.addGoodsLedgerChecks(goods, goodsLedger);
        //触发事件-出库称重异常
        scanEventService.addRecordForReagentUsageAbn(dto, devApiLog);
        return result;
    }

    @Override
    public int scanForRtn(ScanDto dto) {
        int result = 0;
        if (StringUtils.isBlank(dto.getGoodsId())) {
            throw new CommonException("缺失参数:goodsId");
        }
        //获取物品信息
        BizGoods goods = bizGoodsMapper.selectById(dto.getGoodsId());
        if (null == goods) {
            throw new CommonException("物品信息不存在=>" + dto.getGoodsId());
        }
        if (StringUtils.isBlank(dto.getCabinetCode())) {
            throw new CommonException("缺失参数:cabinetCode");
        }
        if (StringUtils.isBlank(dto.getCabinetDoorCode())) {
            throw new CommonException("缺失参数:cabinetDoorCode");
        }
        if (goods.getEnterFlag() == 0) {
            throw new CommonException("管理员扫码入库后方可借用");
        }
        if (goods.getLeaveFlag() == 0) {
            throw new CommonException("借出后方可归还");
        }
        if (goods.getSsbrFlag() == 0) {
            throw new CommonException("不支持扫码归还");
        }
        //查找未归还的物品台账
        GoodsLedgerPageResult goodsLedgerPageResult = bizGoodsLedgerMapper.getNydRecordForGoodsId(goods.getId());
        if (null == goodsLedgerPageResult) {
            throw new CommonException("无借出台账");
        }
        //当前用户
        String userId = StpClientUtil.getLoginIdAsString();
        //获取柜子信息
        BizCabinetDoorResp cabinetDoorResp = bizCabinetDoorMapper.getInfoByCabCodeAndCabDoorCode(dto.getCabinetCode(), dto.getCabinetDoorCode());
        //记录日志
        DevApiLog devApiLog = new DevApiLog();
        devApiLog.setCabinetCode(dto.getCabinetCode());
        devApiLog.setCabinetDoorCode(dto.getCabinetDoorCode());
        devApiLog.setUserId(userId);
        devApiLog.setReqType(95);
        devApiLog.setEventTime(new Date());
        devApiLog.setCreateTime(new Date());
        devApiLog.setGoodsIds(dto.getGoodsId());
        devApiLog.setReagentWeight(dto.getWeigh());
        devApiLog.setReagentWeights(dto.getWeigh());
        devApiLogMapper.insert(devApiLog);
        //更新物品归还
        bizGoodsMapper.updateCabInfoForGoodsByIds(Arrays.asList(dto.getGoodsId()), cabinetDoorResp.getCabinetGroupId(), cabinetDoorResp.getCabinetInfoId(), cabinetDoorResp.getId());
        //更新台账
        BizGoodsLedger goodsLedger = new BizGoodsLedger();
        goodsLedger.setId(goodsLedgerPageResult.getId());
        goodsLedger.setRetApiId(devApiLog.getId());
        goodsLedger.setRetCabinetGroupId(cabinetDoorResp.getCabinetGroupId());
        goodsLedger.setRetCabinetId(cabinetDoorResp.getCabinetInfoId());
        goodsLedger.setRetCabinetDoorId(cabinetDoorResp.getId());
        goodsLedger.setWarehouseTime(devApiLog.getEventTime());
        goodsLedger.setWarehouseUserId(userId);
        if (goods.getGoodsType() == 1) {
            //需要称重 判定——取还间称重次数小于两次
            if (StringUtils.isNotBlank(goods.getReagentWeighNeedFlag())) {
                if (goods.getReagentWeighNeedFlag().equals("1")) {
                    if (StringUtils.isBlank(goodsLedgerPageResult.getReagentOutWeight()) || StringUtils.isBlank(dto.getWeigh())) {
                        //触发事件-取还间称重次数小于两次
                        scanEventService.addRecordForRtnWeighCount(dto, devApiLog);
                    }
                }
            }
            String retWeight = dto.getWeigh();
            goodsLedger.setReagentRetApiId(devApiLog.getId());
            goodsLedger.setReagentRetWeight(retWeight);
            if (StringUtils.isNotBlank(retWeight)) {
                if (goods.getReagentContainerWeight() != null) {
                    //有容器重量时候计算毛重
                    retWeight = NumberUtil.round(NumberUtil.sub(retWeight, goods.getReagentContainerWeight().toString()), 2).toString();
                }

                if (goods.getReagentDensity() != null) {
                    goodsLedger.setReagentRetVolume(NumberUtil.div(retWeight, goods.getReagentDensity().toString(), 2).toString());
                }
                if (StringUtils.isNotBlank(goodsLedgerPageResult.getReagentOutWeight())) {
                    //计算使用了多少
                    BigDecimal useWeight = NumberUtil.round(NumberUtil.sub(goodsLedgerPageResult.getReagentOutWeight(), retWeight), 2);
                    goodsLedger.setReagentUseWeight(useWeight.toString());
                    if (goods.getReagentDensity() != null) {
                        goodsLedger.setReagentUseVolume(NumberUtil.div(useWeight, goods.getReagentDensity(), 2).toString());
                    }
                }
                //处理物品剩余量
                bizGoodsService.handleReagentAvlData(goods, retWeight);
            }
        }
        goodsLedger.setReturnFlag(1);
        int count = bizGoodsLedgerMapper.updateById(goodsLedger);
        result = result + count;
        if (!userId.equals(goodsLedgerPageResult.getDeliveryUserId())) {
            //触发事件-取还人不一致
            scanEventService.addRecordForGoodsBrOfUserAbn(goodsLedgerPageResult, dto, devApiLog);
        }
        if (DateUtil.between(goodsLedgerPageResult.getReturnTime(), devApiLog.getEventTime(), DateUnit.SECOND, false) > 0) {
            //触发事件-物品超期归还
            scanEventService.addRecordForGoodsBrOfOverdue(goodsLedgerPageResult, dto, devApiLog);
        }
        //判断一致性和非一致性
        bizGoodsMapper.updateStoAbcForGoodsByIds(Arrays.asList(dto.getGoodsId()));
        bizGoodsMapper.updateToStoAbcForGoodsByIds(Arrays.asList(dto.getGoodsId()));
        return result;
    }
}
